package com.ai.module.user.service.impl;

import cn.hutool.core.lang.UUID;
import cn.hutool.http.HttpUtil;
import com.ai.module.chat.common.base.ThreadLocalContext;
import com.ai.module.chat.common.constant.RedisKeyStringConstant;
import com.ai.module.chat.common.constant.StringConstant;
import com.ai.module.chat.common.domain.vo.RiskReason;
import com.ai.module.chat.config.advice.exception.BusinessException;
import com.ai.module.business.enu.Source;
import com.ai.module.business.service.BannerRecordService;
import com.ai.module.user.constant.WXConstant;
import com.ai.module.user.domain.entity.UserConfigEntity;
import com.ai.module.user.domain.entity.UserMangeEntity;
import com.ai.module.user.domain.entity.UserRobotEntity;
import com.ai.module.user.domain.req.UserConfigReq;
import com.ai.module.user.domain.req.UserLogin;
import com.ai.module.user.domain.req.WXUserInfo;
import com.ai.module.user.domain.vo.UserLoginInfo;
import com.ai.module.user.enu.VipType;
import com.ai.module.user.mapper.UserMangeMapper;
import com.ai.module.user.service.UserConfigService;
import com.ai.module.user.service.UserMangeService;
import com.ai.module.user.service.UserRobotService;
import com.ai.module.chat.util.DateUtils;
import com.ai.module.chat.util.InviteCodeUtil;
import com.ai.module.chat.util.RedisTemplateUtils;
import com.ai.module.chat.util.aliyun.AliyunUtil;
import com.ai.module.chat.util.aliyun.MessageCodeUtil;
import com.ai.common.BaseResp;
import com.ai.module.mj.constant.stringConstant.ReturnCode;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.StringPool;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.time.LocalDateTime;
import java.util.*;


/**
 * @author: MrHe
 * @create: 2023-09-02 12:16
 * @description:
 **/
@Service
@Slf4j
public class UserMangeServiceImpl extends ServiceImpl<UserMangeMapper, UserMangeEntity> implements UserMangeService {

    @Autowired
    private UserMangeMapper mangeUserMapper;

    @Autowired
    private UserRobotService userRobotService;

    @Autowired
    private UserConfigService userConfigService;

    @Resource
    private RestTemplate restTemplate;

    @Autowired
    private BannerRecordService bannerRecordService;


    @Override
    public UserLoginInfo login(UserLogin userLogin) {
        String phone = userLogin.getPhone();
        String password = userLogin.getPassword();
        Integer phoneCode = userLogin.getPhoneCode();
        if (StringUtils.isBlank(phone)) {
            throw new BusinessException("用户手机号为空");
        }
        UserMangeEntity userMange = this.getOne(new LambdaQueryWrapper<UserMangeEntity>()
                .eq(UserMangeEntity::getPhone, phone));

        if (userMange == null) {
            log.info("用户{}尚未注册,进行自动注册", phone);
            throw new BusinessException("请先注册", ReturnCode.FAILURE);
        }
        // 使用验证码登录
        if (phoneCode !=null ){
            Integer realPhoneCode = RedisTemplateUtils.get(String.format(RedisKeyStringConstant.PHONE_CODE, phone));
            if (! Objects.equals(realPhoneCode,phoneCode )){
                throw new BusinessException("验证码错误", ReturnCode.FAILURE);
            }
            UserLoginInfo userLoginInfo = mangeUserMapper.selectUserInfo(phone, null, null, null);
            return setUserInfo(userLoginInfo);
        }
        if (!Objects.equals(userMange.getPassWord(), password)) {
            throw new BusinessException("用户密码错误");
        }
        UserLoginInfo userLoginInfo = mangeUserMapper.selectUserInfo(phone, password, null, null);
        return setUserInfo(userLoginInfo);
    }


    private UserLoginInfo setUserInfo(UserLoginInfo userLoginInfo) {
        userLoginInfo.setLoginTime(DateUtils.getCurrentTime());
        String loginToken = UUID.randomUUID().toString() + StringPool.AT + DateUtils.getTransDateTimeLogin();
        userLoginInfo.setLoginToken(loginToken);
        HttpServletResponse response = ((ServletRequestAttributes) Objects.requireNonNull(RequestContextHolder.getRequestAttributes())).getResponse();
        String userToken = String.format(RedisKeyStringConstant.USER_INFO, loginToken);
        String userId = userLoginInfo.getUuid();
        String userIdKey = String.format(RedisKeyStringConstant.USER_ID_TOKEN, userId);
        String userOriginalToken = RedisTemplateUtils.get(userIdKey);
        if (StringUtils.isNotBlank(userOriginalToken)){
            // 删除原来的 用户数据
            RedisTemplateUtils.remove(String.format(RedisKeyStringConstant.USER_INFO,userOriginalToken));
        }
        RedisTemplateUtils.set(userToken, userLoginInfo, DateUtils.WEK_DAY);
        RedisTemplateUtils.set(userIdKey,loginToken,DateUtils.WEK_DAY);
        assert response != null;
        //response.setHeader(StringConstant.TOKEN, userToken);
        return userLoginInfo;
    }

    @Override
    public UserLoginInfo register(UserLogin userLogin) {
        String password = userLogin.getPassword();
        String phone = userLogin.getPhone();
        Integer userPhoneCode = userLogin.getPhoneCode();
        checkPhoneCode(userPhoneCode, phone);
        // 先查询验证码是否正确

        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        String remoteUser = request.getRemoteUser();
        int count = mangeUserMapper.selectCount(new LambdaQueryWrapper<UserMangeEntity>()
                .eq(UserMangeEntity::getPhone, phone)
        );
        if (count != 0) {
            throw new BusinessException("用户名已存在");
        }
        UserMangeEntity user = new UserMangeEntity();
        user.setName(phone);
        user.setPhone(phone);
        user.setPassWord(password);
        user.setHost(remoteUser);
        user.setOpenId(userLogin.getOpenId());
        user.setUuid(UUID.randomUUID().toString().toUpperCase(Locale.ROOT));
        mangeUserMapper.insert(user);
        String userId = user.getUuid();
        Integer id = user.getId();
        UserConfigEntity userConfig = new UserConfigEntity();
        userConfig.setUserId(userId);
        userConfig.setInviteCode(InviteCodeUtil.getCode4(id));
        String inviteCode = userLogin.getInviteCode();
        if (StringUtils.isNotBlank(inviteCode)) {
            userConfig.setInviteBy(inviteCode);
        }
        userConfig.setVip(1);
        userConfig.setVipExpire(LocalDateTime.now().plusDays(7));
        userConfig.setPoints(500);
        userConfigService.save(userConfig);
        UserLoginInfo userLoginInfo = new UserLoginInfo();
        BeanUtils.copyProperties(userConfig, userLoginInfo);
        userLoginInfo.setName(phone);
        userLoginInfo.setId(id);
        userLoginInfo.setUuid(user.getUuid());
        userLoginInfo.setVipExpire(DateUtils.format(userConfig.getVipExpire()));
        // 进行AI注册
        UserRobotEntity userRobotChat = new UserRobotEntity();
        userRobotChat.setUserId(userId);
        userRobotChat.setRobotName("默认聊天AI");
        userRobotChat.setRobotType(1);
        userRobotChat.setIsDefault(1);
        UserRobotEntity userRobotDraw = new UserRobotEntity();
        userRobotDraw.setUserId(userId);
        userRobotDraw.setRobotName("默认绘画AI");
        userRobotDraw.setRobotType(2);
        userRobotDraw.setIsDefault(1);

        UserRobotEntity userRobotPrompt = new UserRobotEntity();
        userRobotPrompt.setUserId(userId);
        userRobotPrompt.setRobotName("默认提示词AI");
        userRobotPrompt.setRobotType(3);
        userRobotPrompt.setIsDefault(1);

        UserRobotEntity userRobotAnalyze = new UserRobotEntity();
        userRobotAnalyze.setUserId(userId);
        userRobotAnalyze.setRobotName("默认图片分析AI");
        userRobotAnalyze.setRobotType(4);
        userRobotAnalyze.setIsDefault(1);

        UserRobotEntity userRobotDescription = new UserRobotEntity();
        userRobotDescription.setUserId(userId);
        userRobotDescription.setRobotName("默认图片描述AI");
        userRobotDescription.setRobotType(5);
        userRobotDescription.setIsDefault(1);

        List<UserRobotEntity> defaultRobotList = new ArrayList<>();
        defaultRobotList.add(userRobotDraw);
        defaultRobotList.add(userRobotPrompt);
        defaultRobotList.add(userRobotChat);
        // defaultRobotList.add(userRobotAnalyze);
        // defaultRobotList.add(userRobotDescription);
        userRobotService.saveBatch(defaultRobotList);
        return setUserInfo(userLoginInfo);
    }

    private static void checkPhoneCode(Integer userPhoneCode, String phone) {
        if (userPhoneCode !=null){
            String phoneCodeRedisKey = String.format(RedisKeyStringConstant.PHONE_CODE, phone);
            Integer phoneCode = RedisTemplateUtils.get(phoneCodeRedisKey);
            if (phoneCode == null) {
                throw new BusinessException("验证码已失效",ReturnCode.FAILURE);
            }
            if (!Objects.equals(phoneCode, userPhoneCode)) {
                throw new BusinessException("验证码错误",ReturnCode.FAILURE);
            }
        }
    }

    @Override
    public UserLoginInfo userInfo() {
        String userId = ThreadLocalContext.getUserId();
        if (StringUtils.isBlank(userId)) {
            return new UserLoginInfo();
        }
        UserLoginInfo userLoginInfo = mangeUserMapper
                .selectUserInfo(null, null, ThreadLocalContext.getUserId(), null);
        refreshUserInfo(userLoginInfo);
        return userLoginInfo;
    }
    private void refreshUserInfo(UserLoginInfo userLoginInfo) {
        userLoginInfo.setLoginTime(DateUtils.getCurrentTime());

        String userId = userLoginInfo.getUuid();
        String userIdKey = String.format(RedisKeyStringConstant.USER_ID_TOKEN, userId);
        String userOriginalToken = RedisTemplateUtils.get(userIdKey);
        String userTokenKey = String.format(RedisKeyStringConstant.USER_INFO, userOriginalToken);

        userLoginInfo.setLoginToken(userOriginalToken);
        RedisTemplateUtils.set(userTokenKey, userLoginInfo, DateUtils.WEK_DAY);

    }


    @Override
    public void loginOut() {
        UserLoginInfo userLoginInfo = ThreadLocalContext.getUserLoginInfo();
        String loginToken = (String) ThreadLocalContext.get(StringConstant.TOKEN);
        String userTokenKey = String.format(RedisKeyStringConstant.USER_INFO, loginToken);
        Boolean remove = RedisTemplateUtils.remove(userTokenKey);
        // 删除用户 token
        String userId = userLoginInfo.getUuid();
        RedisTemplateUtils.remove(String.format(RedisKeyStringConstant.USER_ID_TOKEN,userId));
        if (!remove) {
            throw new BusinessException("用户退出失败");
        }
    }

    @Override
    public void updateUser(UserConfigReq userConfigReq) {
        String userName = userConfigReq.getName();
        userName= StringUtils.isBlank(userName) ? userConfigReq.getUserName(): userName;
        if (StringUtils.isNotBlank(userName)){
            RiskReason riskReason = AliyunUtil.getRiskReason(userName);
            Boolean success = riskReason.getSuccess();
            if (!success) {
                bannerRecordService.textCheck(String.join(",", riskReason.getRiskWords()),
                        ThreadLocalContext.getUserId(),
                        userName,
                        Source.USER_NAME
                );
                throw new BusinessException("用户名违反相关规则", ReturnCode.FAILURE);
            }
        }
        UserMangeEntity userEntity = new UserMangeEntity();
        BeanUtils.copyProperties(userConfigReq, userEntity);
        UserConfigEntity userConfig = new UserConfigEntity();
        BeanUtils.copyProperties(userConfigReq, userConfig);
        this.update(userEntity,
             new LambdaQueryWrapper<UserMangeEntity>()
                     .eq(UserMangeEntity::getUuid, ThreadLocalContext.getUserId())
        );
        userConfigService.update(userConfig,
                new LambdaQueryWrapper<UserConfigEntity>()
                        .eq(UserConfigEntity::getUserId, ThreadLocalContext.getUserId())
        );
        // 更新用户数据
        //UserLoginInfo newUser = mangeUserMapper.selectUserInfo(null, null, ThreadLocalContext.getUserId());
        UserLoginInfo realUser = ThreadLocalContext.getUserLoginInfo();
        realUser.setName(userConfigReq.getName());
        realUser.setIcon(userConfigReq.getIcon());
        realUser.setPointsProtocol(userConfigReq.getPointsProtocol());
        String userTokenKey = String.format(RedisKeyStringConstant.USER_INFO, realUser.getLoginToken());
        RedisTemplateUtils.set(userTokenKey, realUser, DateUtils.WEK_DAY);

    }

    @Override
    public void activateMembership(VipType vipType) {

    }

    @Override
    public UserLoginInfo loginByWx(String phone, String code, JSONObject tokenJson) {
        LambdaQueryWrapper<UserMangeEntity> phoneQuery = new LambdaQueryWrapper<UserMangeEntity>()
                .eq(UserMangeEntity::getPhone, phone);
        UserMangeEntity user = this.getOne(phoneQuery);

        UserLogin userLogin = new UserLogin();
        userLogin.setPhone(phone);
        if (user == null) {
           String openId = getOpenId(code, tokenJson);
            log.info("查询到数据库用户信息[{}],openId[{}]",user,openId);
            userLogin.setOpenId(openId);
            return register(userLogin);
        } else {
            // 直接登录就好
            UserLoginInfo userLoginInfo = mangeUserMapper.selectUserInfo(phone, null, null, null);
            return setUserInfo(userLoginInfo);
        }
    }

    private String getOpenId(String code, JSONObject tokenJson) {
        Map<String, Object> paramMap = new HashMap<>();
        paramMap.put("code", code);
        String openUrl = "https://api.weixin.qq.com/wxa/getpluginopenpid?access_token=" + tokenJson.getString("access_token");
        JSONObject openReturnJson = restTemplate.postForObject(openUrl, JSONObject.toJSONString(paramMap), JSONObject.class);
        // openpid
        String openId = openReturnJson.getString("openpid");
        log.info("获取到的openInfo[{}]", openReturnJson);
        return openId;
    }

    @Override
    public UserLoginInfo wxUserInfo(WXUserInfo userInfo) {
        String code = userInfo.getCode();
        // 获取token
        String token_url = String.format("https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=%s&secret=%s", WXConstant.APPID, WXConstant.SECRET);
        JSONObject token = JSON.parseObject(HttpUtil.get(token_url));
        String openId = getOpenId(code, token);
        WXUserInfo.RealUserInfo realUserInfo = userInfo.getRealUserInfo();
        String nickName = realUserInfo.getNickName();
        String avatarUrl = realUserInfo.getAvatarUrl();
        LambdaQueryWrapper<UserMangeEntity> phoneQuery = new LambdaQueryWrapper<UserMangeEntity>()
                .eq(UserMangeEntity::getOpenId, openId);
        UserMangeEntity user = this.getOne(phoneQuery);

        UserLogin userLogin = new UserLogin();
        userLogin.setOpenId(openId);
        userLogin.setName(nickName);
        userLogin.setAvatarUrl(avatarUrl);
        if (user == null) {
            log.info("查询到数据库用户信息[{}],openId[{}]",user,openId);
            userLogin.setOpenId(openId);
            return register(userLogin);
        } else {
            // 直接登录就好
            UserLoginInfo userLoginInfo = mangeUserMapper.selectUserInfo(null, null, null,openId);
            return setUserInfo(userLoginInfo);
        }
    }

    @Override
    public BaseResp sendMessage(UserLogin userInfo) {
        // 创建数据
        String phone = userInfo.getPhone();
        Integer phoneCode = userInfo.getPhoneCode();

        if (phoneCode == null || phoneCode > 99999) {
            phoneCode = InviteCodeUtil.getMessageCode(5);
        }
        MessageCodeUtil.SendMessageCode(phoneCode, phone);
        String phoneCodeKey = String.format(RedisKeyStringConstant.PHONE_CODE, phone);
        RedisTemplateUtils.set(phoneCodeKey, phoneCode, DateUtils.TIME_MIN * 5);
        return BaseResp.success(phoneCode);
    }
}
